// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包编辑实现基于缓冲位置的字节片编辑。
package edit

import (
	"fmt"
	"sort"
)

// 缓冲区是应用于给定字节片的编辑队列。
type Buffer struct {
	old []byte
	q   edits
}

// 编辑记录单个文本修改：更改中的字节[开始，结束]到新。编辑是一个编辑列表，可按开始偏移量排序，按结束偏移量断开连接。新缓冲区返回一个新缓冲区，以累积对初始数据片的更改。返回的缓冲区保留对数据的引用，因此调用方必须确保直到缓冲区被删除后才修改数据一个正在使用。
type edit struct {
	start int
	end   int
	new   string
}

type edits []edit

func (x edits) Len() int      { return len(x) }
func (x edits) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x edits) Less(i, j int) bool {
	if x[i].start != x[j].start {
		return x[i].start < x[j].start
	}
	return x[i].end < x[j].end
}

func NewBuffer(data []byte) *Buffer {
	return &Buffer{old: data}
}

func (b *Buffer) Insert(pos int, new string) {
	if pos < 0 || pos > len(b.old) {
		panic("invalid edit position")
	}
	b.q = append(b.q, edit{pos, pos, new})
}

func (b *Buffer) Delete(start, end int) {
	if end < start || start < 0 || end > len(b.old) {
		panic("invalid edit position")
	}
	b.q = append(b.q, edit{start, end, ""})
}

func (b *Buffer) Replace(start, end int, new string) {
	if end < start || start < 0 || end > len(b.old) {
		panic("invalid edit position")
	}
	b.q = append(b.q, edit{start, end, new})
}

// Bytes返回一个新的字节片，其中包含应用排队编辑的原始数据
// 。
func (b *Buffer) Bytes() []byte {
	// 按开始位置和结束位置对编辑进行排序。
	// 通过结束位置断开连接，允许在替换[x，y]处的文本之前应用点x处的插入
	// 字符串返回包含原始数据的字符串
	sort.Stable(b.q)

	var new []byte
	offset := 0
	for i, e := range b.q {
		if e.start < offset {
			e0 := b.q[i-1]
			panic(fmt.Sprintf("overlapping edits: [%d,%d)->%q, [%d,%d)->%q", e0.start, e0.end, e0.new, e.start, e.end, e.new))
		}
		new = append(new, b.old[offset:e.start]...)
		offset = e.end
		new = append(new, e.new...)
	}
	new = append(new, b.old[offset:]...)
	return new
}

// 并应用排队编辑。
func (b *Buffer) String() string {
	return string(b.Bytes())
}
